package com.yyw.foodie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.yyw.foodie.bo.cart.ShopCartBo;
import com.yyw.foodie.bo.orders.OrderItemDto;
import com.yyw.foodie.bo.orders.SubmitOrderBo;
import com.yyw.foodie.common.Result;
import com.yyw.foodie.constant.BaseConstant;
import com.yyw.foodie.enums.OrderEnums;
import com.yyw.foodie.enums.YesOrNoEnums;
import com.yyw.foodie.exceptions.NullParamException;
import com.yyw.foodie.exceptions.OrderStatusException;
import com.yyw.foodie.exceptions.PayException;
import com.yyw.foodie.mapper.OrdersMapper;
import com.yyw.foodie.pojo.*;
import com.yyw.foodie.service.*;
import com.yyw.foodie.utils.*;
import com.yyw.foodie.vo.center.order.MainOrder;
import com.yyw.foodie.vo.center.order.OrderTrend;
import com.yyw.foodie.vo.pay.MerchantOrdersVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单表; 服务实现类
 * </p>
 *
 * @author yiyw
 * @since 2021-05-22
 */
@Slf4j
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, OrdersEntity> implements OrdersService {


    @Autowired
    private UserAddressService addressService;

    @Autowired
    private ItemsSpecService itemsSpecService;

    @Autowired
    private OrderItemsService orderItemsService;

    @Autowired
    private OrderStatusService orderStatusService;

    @Autowired
    private UsersService usersService;

    @Autowired
    private OrdersMapper ordersMapper;

    @Autowired
    private RedisOperator redisOperator;

    /**
     * 聚合支付平台地址，用来发起支付的
     */
    @Value("${pay.paymentUrl}")
    private String paymentUrl;

    /**
     * 聚合支付回调我们的地址，用来支付成功后通知我们
     */
    @Value("${pay.payReturnUrl}")
    private String payReturnUrl;

    @Autowired
    private RestTemplate restTemplate;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public String createOrder(SubmitOrderBo submitOrderBo) {
        // 1.创建主订单
        OrdersEntity orderMaster = new OrdersEntity();
        orderMaster.setLeftMsg(submitOrderBo.getLeftMsg());
        orderMaster.setPayMethod(submitOrderBo.getPayMethod());
        orderMaster.setIsComment(YesOrNoEnums.否.code);
        orderMaster.setIsDelete(YesOrNoEnums.否.code);
        orderMaster.setUserId(submitOrderBo.getUserId());
        // 1.1 获取收货信息
        UserAddressEntity addressEntity = addressService.getById(submitOrderBo.getAddressId());
        if (null == addressEntity) {
            throw new NullParamException("未找到收货地址信息, 地址ID: " + submitOrderBo.getAddressId());
        }
        // 1.2 获取用户信息
        UsersEntity user = usersService.getById(submitOrderBo.getUserId());
        if (null == user) {
            throw new NullParamException("未找到用户信息，userId: " + submitOrderBo.getUserId());
        }

        orderMaster.setReceiverName(addressEntity.getReceiver());
        orderMaster.setReceiverMobile(addressEntity.getMobile());
        String address = addressEntity.getProvince() + " "
                + addressEntity.getCity() + " " + addressEntity.getDistrict()
                + " " + addressEntity.getDetail();
        orderMaster.setReceiverAddress(address);
        // 邮费,默认是包邮 0元
        Integer postAmount = 0;
        orderMaster.setPostAmount(postAmount);
        // 递增订单总金额
        Integer totalAmount = 0;
        // 递增订单实际支付总金额
        Integer realPayAmount = 0;

        // 2.循环创建从订单
        String skuIds = submitOrderBo.getItemSpecIds();
        String[] skuArrays = skuIds.split(",");
        // 收集要保存的子订单信息
        List<OrderItemsEntity> orderItemsList = new ArrayList<>();
        for (String sku : skuArrays) {
            // 获取SKU 信息
            OrderItemDto itemDto = itemsSpecService.getItemByPay(sku);
            if (null == itemDto) {
                throw new NullParamException("未找到商品信息, sku: " + sku);
            }

            // 2.1 扣减库存
            // 从redis缓存中获取下单数量
            Integer buyCount = getBuyCountByRedis(sku, user.getId());
            Boolean flag = itemsSpecService.minusStock(sku, buyCount);
            log.info("{} 商品库存: {}", sku, flag);
            if (!flag) {
                throw new RuntimeException("商品:" + itemDto.getItemName() + ", 规格: " + itemDto.getItemSpecName() + " 该商品库存不足");
            }

            // 2.2 拼接信息
            OrderItemsEntity item = new OrderItemsEntity();
            BeanUtils.copyProperties(itemDto, item);
            item.setBuyCounts(buyCount);
            orderItemsList.add(item);

            // 2.3 累加金额
            totalAmount += itemDto.getPriceNormal();
            realPayAmount += item.getPrice();
        }

        // 4. 保存订单主表
        orderMaster.setTotalAmount(totalAmount);
        orderMaster.setRealPayAmount(realPayAmount);
        save(orderMaster);

        // 5. 保存订单子表
        for (OrderItemsEntity itemsEntity : orderItemsList) {
            itemsEntity.setOrderId(orderMaster.getId());
        }
        orderItemsService.saveBatch(orderItemsList);

        // 6. 创建订单状态表
        OrderStatusEntity statusEntity = new OrderStatusEntity();
        statusEntity.setOrderStatus(OrderEnums.待付款.code);
        statusEntity.setOrderId(orderMaster.getId());
        orderStatusService.save(statusEntity);

        // 7. 构建商户订单，发送请求
        buildMerchantOrder(orderMaster);

        return orderMaster.getId();
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public PagedGridResult getOrderInfo(String userId, Integer orderStatus, Integer page, Integer pageSize) {
        PageHelper.startPage(page, pageSize);
        List<MainOrder> info = ordersMapper.getOrderInfoByPage(userId, orderStatus);
        PagedGridResult pagedGridResult = PagedGridResult.setterPagedGrid(info, page);
        return pagedGridResult;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Boolean deliver(String orderId) {
        // 1. 查询订单状态信息
        QueryWrapper<OrderStatusEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OrderStatusEntity::getOrderId, orderId);
        OrderStatusEntity entity = orderStatusService.getOne(queryWrapper);
        if (entity == null) {
            throw new OrderStatusException("未查到订单信息,更新失败!");
        }
        if (!OrderEnums.已付款待发货.code.equals(entity.getOrderStatus())) {
            throw new OrderStatusException("订单状态不正确或已发货,更新失败!");
        }
        UpdateWrapper<OrderStatusEntity> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(OrderStatusEntity::getOrderId, orderId)
                .set(OrderStatusEntity::getOrderStatus, OrderEnums.待收货.code)
                .set(OrderStatusEntity::getDeliverTime, new Date());
        return orderStatusService.update(updateWrapper);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Boolean deleteOrder(String userId, String orderId) {
        // 1. 查询订单信息，判断是否是自己的订单
        // TODO: 2021/6/3 此处先暂时使用传入的用户ID，后面使用从redis获取当前登入用户
        QueryWrapper<OrdersEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OrdersEntity::getId, orderId)
                .eq(OrdersEntity::getUserId, userId)
                .eq(OrdersEntity::getIsDelete, YesOrNoEnums.否.code);
        OrdersEntity entity = getOne(queryWrapper);
        if (entity == null) {
            throw new OrderStatusException("未查到订单信息,删除失败!");
        }
        // 修改状态
        entity.setIsDelete(YesOrNoEnums.是.code);
        return updateById(entity);
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Boolean confirmReceive(String userId, String orderId) {
        // 1. 查询订单状态信息
        QueryWrapper<OrderStatusEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OrderStatusEntity::getOrderId, orderId);
        OrderStatusEntity entity = orderStatusService.getOne(queryWrapper);
        if (entity == null) {
            throw new OrderStatusException("未查到订单信息,更新失败!");
        }
        if (!OrderEnums.待收货.code.equals(entity.getOrderStatus())) {
            throw new OrderStatusException("订单状态不正确或已发货,更新失败!");
        }
        // 2. 更新状态
        UpdateWrapper<OrderStatusEntity> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(OrderStatusEntity::getOrderId, orderId)
                .set(OrderStatusEntity::getOrderStatus, OrderEnums.交易成功.code)
                .set(OrderStatusEntity::getSuccessTime, new Date());
        return orderStatusService.update(updateWrapper);
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void closeOrder() {
        // 查询所有未支付的订单信息
        QueryWrapper<OrderStatusEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OrderStatusEntity::getOrderStatus, OrderEnums.待付款.code);
        List<OrderStatusEntity> list = orderStatusService.list(queryWrapper);
        if (!CollectionUtils.isEmpty(list)) {
            List<OrderStatusEntity> collect = list.stream().filter(e -> {
                Date createdTime = e.getCreatedTime();
                int i = DateUtil.daysBetween(createdTime, new Date());
                return i >= 1;
            }).map(e -> {
                e.setCloseTime(new Date());
                e.setOrderStatus(OrderEnums.交易关闭.code);
                return e;
            }).collect(Collectors.toList());
            log.info("要关闭的订单数量有: {}", collect.size());
            log.info("要关闭的订单信息: {}", collect.toString());
            orderStatusService.updateBatchById(collect);
            log.info("关闭订单成功");
        }
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public PagedGridResult getOrderTrendPage(String userId, Integer page, Integer pageSize) {
        PageHelper.startPage(page, pageSize);
        List<OrderTrend> orderTrends = ordersMapper.getOrderTrends(userId);
        PagedGridResult result = PagedGridResult.setterPagedGrid(orderTrends, page);
        return result;
    }

    /**
     * 订单创建成功，删除购物车缓存
     *
     * @param itemSpecIds 要删除的skuID
     * @param userId      用户ID
     * @param request
     * @param response
     */
    @Override
    public void removeCatBySku(String itemSpecIds, String userId, HttpServletRequest request, HttpServletResponse response) {
        String value = redisOperator.get(BaseConstant.CACHE_CAT + userId);
        if (StringUtils.isBlank(value)) {
            throw new RuntimeException("购物车数据为空，无法删除商品");
        }
        String[] ids = itemSpecIds.split(",");
        List<ShopCartBo> shopCartBos = JsonUtils.jsonToList(value, ShopCartBo.class);
        List<ShopCartBo> removeEl = new ArrayList<>();
        for (ShopCartBo bo : shopCartBos) {
            for (String skuId : ids) {
                if (Objects.equals(bo.getSpecId(), skuId)) {
                    removeEl.add(bo);
                }
            }
        }
        if (shopCartBos.size() == removeEl.size()) {
            // 删除缓存
            redisOperator.del(BaseConstant.CACHE_CAT + userId);
            CookieUtils.deleteCookie(request, response, BaseConstant.SHOPCART);
        } else {
            shopCartBos.removeAll(removeEl);
            String json = JsonUtils.objectToJson(shopCartBos);
            redisOperator.set(BaseConstant.CACHE_CAT + userId, JsonUtils.objectToJson(shopCartBos));
            CookieUtils.setCookie(request, response, BaseConstant.SHOPCART, json, true);
        }
    }


    /**
     * 构建商户订单，并且发送请求给商户中心
     *
     * @param orderMaster 订单信息
     */
    private void buildMerchantOrder(OrdersEntity orderMaster) {
        // 构建实体
        MerchantOrdersVO ordersVO = new MerchantOrdersVO();
        ordersVO.setMerchantOrderId(orderMaster.getId());
        ordersVO.setMerchantUserId(orderMaster.getUserId());
        // 构建金额，这里设置金额为1分钱
        ordersVO.setAmount(1);
        ordersVO.setPayMethod(orderMaster.getPayMethod());
        ordersVO.setReturnUrl(payReturnUrl);

        // 构建请求头信息
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        httpHeaders.add("imoocUserId", "imooc");
        httpHeaders.add("password", "imooc");
        HttpEntity<MerchantOrdersVO> httpEntity = new HttpEntity<>(ordersVO, httpHeaders);
        // 向支付中心发送请求
        log.info("准备向支付中心发起请求，请求内容: {}", httpEntity.toString());
        ResponseEntity<Result> response = restTemplate.postForEntity(paymentUrl, httpEntity, Result.class);
        Result result = response.getBody();
        if (HttpStatus.OK.value() != result.getStatus()) {
            log.error("发送错误：{}", result.getMsg());
            throw new PayException("支付中心订单创建失败，请联系管理员！");
        }
        log.info("向支付中心发送请求成功...");
    }


    private Integer getBuyCountByRedis(String skuId, String userId) {
        String val = redisOperator.get(BaseConstant.CACHE_CAT + userId);
        Integer count = null;
        if (StringUtils.isBlank(val)) {
            throw new RuntimeException("购物车数据为空，无法下单");
        }
        List<ShopCartBo> shopCartBos = JsonUtils.jsonToList(val, ShopCartBo.class);
        for (ShopCartBo bo : shopCartBos) {
            if (Objects.equals(bo.getSpecId(), skuId)) {
                count = bo.getBuyCounts();
            }
        }
        if (count == null) {
            throw new RuntimeException("购物车中未找到skuId： " + skuId + "商品，无法下单");
        }
        return count;
    }
}
